// Filter Code Description:
// 1. 1signal.cpp: Code for generating virtual signals with noise.
// 2. menu2.cpp: Code for applying the filter to the noisy signal.
// 3. 2signal_data.csv: File to store coordinates of the noisy signal for visualization.
// 4. 5Filtered_signal.csv: File to store coordinates of the filtered signal for visualization.
// 5. 3time_and_frequency_picture.py: Python script for plotting the noisy signal.
// 6. 6after_time_and_f_picture.py: Python script for plotting the filtered signal.

// Execution Sequence:
// 1. Run 1signal.cpp to generate a noisy signal and save it in 2signal_data.csv.
// 2. Use 3time_and_frequency_picture.py to plot the noisy signal from 1signal_data.csv.
// 3. Run menu2.cpp to apply filtering and save the filtered signal in 5Filtered_signal.csv.
// 4. Use 6after_time_and_f_picture.py to plot the filtered signal from 5Filtered_signal.csv.

// Junhao Deng 2022115934 2024.12
 
#include "menu2.h"
#include "1signal.h"

// Constructor: Hardcoded input and output filenames, RC constant, and time step
SignalFilter::SignalFilter()
    : input_filename_("2signal_data.csv"), output_filename_("5Filtered_signal.csv"), RC_(1.0), dt_(1) {}

// Split a string by a comma delimiter
std::vector<std::string> SignalFilter::split(const std::string& s, char delimiter) {
    std::vector<std::string> tokens;
    std::string token;
    std::istringstream tokenStream(s);
    while (getline(tokenStream, token, delimiter)) {
        tokens.push_back(token);
    }
    return tokens;
}

void Loadingtime2(int repeatCount) {
    for (int i = 0; i < repeatCount; ++i) {
        cout << "\rProcessing"; 
        for (int j = 0; j <= i % 5; ++j) {
            cout << "."; 
        }
        cout.flush(); 
        this_thread::sleep_for(chrono::milliseconds(500)); 
    }
    cout << endl; 
    cout << "\033c";
}

// Process the file and apply low-pass filtering
void SignalFilter::processFile() {
    std::ifstream inFile(input_filename_);
    std::ofstream outFile(output_filename_);
    std::string line;

    if (!inFile.is_open() || !outFile.is_open()) {
        std::cerr << "Error opening file." << std::endl;
        return;
    }

    // Calculate smoothing factor alpha
    const double alpha = dt_ / (RC_ + dt_);
    double previous_output = 0.0;  // Previous filtered value

    // Write the header to the output file
    outFile << "Time,FilteredSignal" << std::endl;

    while (getline(inFile, line)) {
        std::vector<std::string> data = split(line, ',');
        if (data.size() == 2) {
            try {
                double time = std::stod(data[0]);
                double value = std::stod(data[1]);
                // RC low-pass filter formula
                double filtered_value = alpha * value + (1 - alpha) * previous_output;
                previous_output = filtered_value;
                // Write the filtered value to the output file
                outFile << time << ", " << filtered_value << std::endl;
            } 
            catch (const std::exception& e) {
                std::cerr << "Error parsing line '" << line << "': " << e.what() << std::endl;
                continue;
            }
        }
    }

    Loadingtime2(5);
    cout << "\n******************************************" << endl;
    cout << "*            Original signal             *" << endl;
    cout << "******************************************" << endl;
    cout << "The 'original signal' has been generated, please check data and wave picture!\n";
    std::cin.get();

    cout << "Press Enter to filter the signal.\n"; 
    std::cin.get();
    
    Loadingtime2(5);
    cout << "\n******************************************" << endl;
    cout << "*            Filtered signal             *" << endl;
    cout << "******************************************" << endl;
    cout << "The 'filtered signal' has been generated, please check data and wave picture!\n";
    cout << "Press Enter to go back to Tools.\n"; 
    std::cin.get();
    Loadingtime2(5);
    
    inFile.close();
    outFile.close();
}

// Main method: Apply low-pass filtering
void SignalFilter::applyLowPassFilter() {
    processFile();
}

// General function: Call in the main function to process the signal
void process_signal() {
    SignalFilter filter;
    filter.applyLowPassFilter();
}
